-
Notifications
You must be signed in to change notification settings - Fork 511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial POC for modify-image #3136
Conversation
This adds in a target for import-images and modify-image with basic support. There is more to come around SELinux and tidying up how we treat CA Bundles and tracking the changes.
#bottlerocket-${BUILDSYS_VARIANT}-${BUILDSYS_ARCH}-${VERSION}-${HASH}-root.verity.lz4 | ||
|
||
if [ -s "${bootlz4}" ] || [ -s "${imglz4}" ] || [ -s "${rootlz4}" ] || [ -s "${hashlz4}" ]; then | ||
echo "Image files already exist for the current version/commit - ${IMAGE} - please run 'cargo make clean' to remove them" >&2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should have a clean-images task so we don't blow out all the docker and rpm stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that seems reasonable. I was focusing on CI/CD flows but it stands to reason one might have other builds in their directory that they don't want cleaned.
# variant-arch-version | ||
# variant-arch-version(with-v) | ||
VERSION=$(echo "${BUILDSYS_VERSION_BUILD}"| cut -f1 -d"-") | ||
ln -s "${OUTDIR}/${bootlz4}" "${OUTDIR}/bottlerocket-${BUILDSYS_VARIANT}-${BUILDSYS_ARCH}-boot.ext4.lz" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems problematic in that you need to have the right sha checked out for this to match what was downloaded, right?
Are we letting the symlinks point at this from our current git sha even if it doesn't match the git sha of the downloaded image?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems problematic in that you need to have the right sha checked out for this to match what was downloaded, right?
No, you don't actually need the SHA checked out which is one of the primary desires of this logic, to avoid having to fiddle with getting that just right, instead you simply need to know the version/hash to download from the repo and then it will create it, this makes me realize I didn't show the structure of the build directory:
$ ls -al build/images/x86_64-metal-k8s-1.25
...
... 1.12.0-6ef1139f
... latest -> 1.12.0-6ef1139f
$ ls -al build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f
...
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-boot.ext4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-boot.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f.img.lz4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.ext4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.verity.lz4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-boot.ext4.lz -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-boot.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0.img.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f.img.lz4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-root.ext4.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64-1.12.0-root.verity.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.verity.lz4
bottlerocket-metal-k8s-1.25-x86_64-boot.ext4.lz -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-boot.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64.img.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f.img.lz4
bottlerocket-metal-k8s-1.25-x86_64-root.ext4.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64-root.verity.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.verity.lz4
bottlerocket-metal-k8s-1.25-x86_64-v1.12.0-boot.ext4.lz -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-boot.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64-v1.12.0.img.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f.img.lz4
bottlerocket-metal-k8s-1.25-x86_64-v1.12.0-root.ext4.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.ext4.lz4
bottlerocket-metal-k8s-1.25-x86_64-v1.12.0-root.verity.lz4 -> /storage/yeazelm/git/yeazelm-br/build/images/x86_64-metal-k8s-1.25/1.12.0-6ef1139f/bottlerocket-metal-k8s-1.25-x86_64-1.12.0-6ef1139f-root.verity.lz4
Are we letting the symlinks point at this from our current git sha even if it doesn't match the git sha of the downloaded image?
We move the symlinks to that point in time specifically for that version within the build, this is always the case for a particular build with a SHA, but won't affect a different builds. This is all within the versioned directory. We could avoid touching the build/images/${VARIANT_NAME}/latest
link but I found it useful for finding the right thing. Its debatable if its "right" or not.
''' | ||
] | ||
|
||
[tasks.modify-image-shell] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get what this task is in relation to modify-image
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been here to simulate the env of modify-image
but be interactive. It won't make the final PR but is here for debugging while I work through the issues.
# Build path | ||
tuftool download \ | ||
"${OUTDIR}" \ | ||
--target-name "${bootlz4}" \ | ||
--target-name "${imglz4}" \ | ||
--target-name "${rootlz4}" \ | ||
--target-name "${hashlz4}" \ | ||
--root ./root.json \ | ||
--metadata-url "https://updates.bottlerocket.aws/2020-07-07/${BUILDSYS_VARIANT}/${BUILDSYS_ARCH}/" \ | ||
--targets-url "https://updates.bottlerocket.aws/targets/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend splitting this up into two parts, maybe two tasks:
- a pubsys invocation to pull down the images into the
build/repos
structure - a buildsys invocation to import images from that local structure into the
build/images
structure
The current convention is for tuftool
invocations to be wrapped by pubsys
and I'd like to keep that.
I feel stronger about the buildsys
approach since ideally we'd use similar Dockerfile targets and refactor out the shell functions to handle the symlinks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense. I mostly wrote this to help me test the actual modification flow but I agree putting this into pubsys
and buildsys
is a better place. I'll add some tasks to get that work done.
docker run --rm -it \ | ||
--user "$(id -u):$(id -g)" \ | ||
--security-opt label:disable \ | ||
-e CARGO_HOME="/tmp/.cargo" \ | ||
-v "${CARGO_HOME}":/tmp/.cargo \ | ||
-v "${BUILDSYS_ROOT_DIR}/tools":/tmp/tools \ | ||
-v "${BUILDSYS_OUTPUT_DIR}":/tmp/build \ | ||
-v "${CA_BUNDLE}":/tmp/ca-bundle.crt \ | ||
-v "${NEW_ROOT_JSON}":/tmp/root.json \ | ||
"${BUILDSYS_SDK_IMAGE}" \ | ||
bash -c "${run_modify_image}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like this to be another buildsys
invocation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had not looked at buildsys
very deeply when writing this but after looking at buildsys
more I think I understand where this would live. Are you thinking of this as a third stage in the Dockerfile as well or some other path I'm not seeing for this logic?
ROOT_START="$(sgdisk --print "${IMAGE}" | awk '/BOTTLEROCKET-ROOT-A/{ print $2 }')" | ||
echo ${ROOT_START} | ||
ROOT_END="$(sgdisk --print "${IMAGE}" | awk '/BOTTLEROCKET-ROOT-A/{ print $3 }')" | ||
echo ${ROOT_END} | ||
ROOT_SIZE="$(( ROOT_END - ROOT_START + 1))" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might help to associate units with these - sectors, bytes, whatever - since it's not immediately obvious what the fields we're cutting out of sgdisk
output. If sgdisk --info
lets us match lines by a prefix then that might help too.
Maybe a helper function that takes a partition name and makes a couple sgdisk
calls to find it and populate the variables that the caller passes in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call out, I like the helper function idea!
# Create the full manifest of modifications for writing to trust-roots.json | ||
echo -e "The full list of json is: ${CHANGED_ROOTS[@]}" | ||
MODIFIED_JSON="$(jq --raw-output . <<< "${CHANGED_ROOTS[@]}")" | ||
|
||
FULL_MODIFIED_JSON="$(jq --slurp 'sort_by(.Name)' <<< "${MODIFIED_JSON}" | jq '{"ModifiedRootsOfTrust": .}')" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have doubts about creating this manifest as a file in the image, but I could see adding this as an additional output for any newly built or modified image.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the primary value of this file is for image self-reference. One can use the image or booted OS directly to determine what is present and not rely upon build logs to determine this. I think of this similarly to the application-inventory.json
where this data can be gleaned from the git repo and build logs but it can be convenient to have this data directly in the image. The main difference between the application inventory and this file is that this trust-roots file could be easily generated from the image/files on the filesystem directly. So if one does care about these files, they can find them and hash them themselves. So all in all, this is mostly a nice to have and the build output is probably valuable and I could be convinced to not include it in the image directly.
--image=*) IMAGE_PATH="${optarg}" ;; | ||
--image-out=*) OUT_IMAGE="${optarg}" ;; | ||
--new-root=*) ROOTFILE="${optarg}" ;; | ||
--ca-bundle=*) CABUNDLE="${optarg}" ;; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't solve for a few use cases we probably need, notably:
- Secure Boot
- OVA image formats
# Build path | ||
tuftool download \ | ||
"${OUTDIR}" \ | ||
--target-name "${bootlz4}" \ | ||
--target-name "${imglz4}" \ | ||
--target-name "${rootlz4}" \ | ||
--target-name "${hashlz4}" \ | ||
--root ./root.json \ | ||
--metadata-url "https://updates.bottlerocket.aws/2020-07-07/${BUILDSYS_VARIANT}/${BUILDSYS_ARCH}/" \ | ||
--targets-url "https://updates.bottlerocket.aws/targets/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense. I mostly wrote this to help me test the actual modification flow but I agree putting this into pubsys
and buildsys
is a better place. I'll add some tasks to get that work done.
docker run --rm -it \ | ||
--user "$(id -u):$(id -g)" \ | ||
--security-opt label:disable \ | ||
-e CARGO_HOME="/tmp/.cargo" \ | ||
-v "${CARGO_HOME}":/tmp/.cargo \ | ||
-v "${BUILDSYS_ROOT_DIR}/tools":/tmp/tools \ | ||
-v "${BUILDSYS_OUTPUT_DIR}":/tmp/build \ | ||
-v "${CA_BUNDLE}":/tmp/ca-bundle.crt \ | ||
-v "${NEW_ROOT_JSON}":/tmp/root.json \ | ||
"${BUILDSYS_SDK_IMAGE}" \ | ||
bash -c "${run_modify_image}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had not looked at buildsys
very deeply when writing this but after looking at buildsys
more I think I understand where this would live. Are you thinking of this as a third stage in the Dockerfile as well or some other path I'm not seeing for this logic?
ROOT_START="$(sgdisk --print "${IMAGE}" | awk '/BOTTLEROCKET-ROOT-A/{ print $2 }')" | ||
echo ${ROOT_START} | ||
ROOT_END="$(sgdisk --print "${IMAGE}" | awk '/BOTTLEROCKET-ROOT-A/{ print $3 }')" | ||
echo ${ROOT_END} | ||
ROOT_SIZE="$(( ROOT_END - ROOT_START + 1))" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call out, I like the helper function idea!
# Create the full manifest of modifications for writing to trust-roots.json | ||
echo -e "The full list of json is: ${CHANGED_ROOTS[@]}" | ||
MODIFIED_JSON="$(jq --raw-output . <<< "${CHANGED_ROOTS[@]}")" | ||
|
||
FULL_MODIFIED_JSON="$(jq --slurp 'sort_by(.Name)' <<< "${MODIFIED_JSON}" | jq '{"ModifiedRootsOfTrust": .}')" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the primary value of this file is for image self-reference. One can use the image or booted OS directly to determine what is present and not rely upon build logs to determine this. I think of this similarly to the application-inventory.json
where this data can be gleaned from the git repo and build logs but it can be convenient to have this data directly in the image. The main difference between the application inventory and this file is that this trust-roots file could be easily generated from the image/files on the filesystem directly. So if one does care about these files, they can find them and hash them themselves. So all in all, this is mostly a nice to have and the build output is probably valuable and I could be convinced to not include it in the image directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocking for Makefile.toml changes.
Issue number: 2486
Closes #
Description of changes:
This adds in a target for import-images and modify-image with basic support. There is more to come around SELinux and tidying up how we treat CA Bundles and tracking the changes.
This is incomplete and needs more testing, but is in an MVP of sorts. There are comments about what to do about incomplete files for bringing in the entire repo. Ideally,
import-images
moves into buildsys or pubsys anyway, so this is more of just a quick helper for the time being anyway.There is more work to do around importing the kmod-kit and migrations for a complete treatment of importing artifacts one might need, but for now, this solves the "how do I modify an image" problem.
Testing done:
Validated with metal images via calling:
Debugfs shows files have the right context:
The
/usr/share/bottlerocket/trust-roots.json
has the contents updated:Terms of contribution:
By submitting this pull request, I agree that this contribution is dual-licensed under the terms of both the Apache License, version 2.0, and the MIT license.